
// panel object
local PANEL = { };


/*------------------------------------
	initialize the file dialog
------------------------------------*/
function PANEL:Init( )

	// set the dialog title
	self:SetTitle( "#musex_filedialog_title" );
	
	// setup the window
	self:SetDraggable( true );
	self:SetDeleteOnClose( false );
	
	// create the folders list
	self.Folders = vgui.Create( "MXComboBox" );
	// don't allow them to select multiple folders
	self.Folders:SetMultiple( false );
	
	// create the files list
	self.Files = vgui.Create( "MXListView" );
	// create the filename column
	self.Files:AddColumn( "#musex_filedialog_filename" );
	// create the size column
	local col = self.Files:AddColumn( "#musex_filedialog_filesize" );
	// set the minimum and maximum size of the file size column
	col:SetMinWidth( 30 );
	col:SetMaxWidth( 80 );
	// store the main file dialog for later use
	self.Files.FileDialog = self;
	// setup the double click function
	self.Files.DoDoubleClick = function( self, lineid, line )
	
		// get the selected lines
		local selected = self:GetSelected();
		
		// only grab the first one
		if ( selected[ 1 ] ) then
		
			// get the filename
			local filename = selected[ 1 ].Filename;
			
			// make sure its not the "no media files" line
			if ( filename == "__nomedia__" ) then
			
				// leave!
				return;
				
			end
			
			// add the file to the playlist
			MuseX.AddToPlaylist( { filename } );
			
			// trick the cancel button into thinking we clicked it (to close the panel)
			self.FileDialog.Cancel.DoClick( self.FileDialog.Cancel );
			
		end
	end
	
	// create the divider
	self.Divider = vgui.Create( "MXHorizontalDivider", self );
	// set the width of the divider
	self.Divider:SetDividerWidth( 6 );
	// set the minimum sizes for both sides
	self.Divider:SetRightMin( 150 );
	self.Divider:SetLeftWidth( MuseX.GetSetting( "filedivider", MXSETTING_NUM ) or 150 );
	// load the controls into the sides of the divider
	self.Divider:SetLeft( self.Folders );
	self.Divider:SetRight( self.Files );
	// setup the OnResized event
	self.Divider.OnResized = function( self ) MuseX.SetSetting( "filedivider", self:GetLeftWidth() ); end;
	
	// create the okay button
	self.Okay = vgui.Create( "MXButton", self );
	// set the text
	self.Okay:SetText( "#musex_okay" );
	// setup the okay button click function
	self.Okay.DoClick = function( self )
	
		// get all of the selected lines
		local selected = self.GetParent( self ).Files.GetSelected( self.GetParent( self ).Files );
		
		// empty song list
		local songs = {};
		
		// loop through all of the selected lines
		for _, s in pairs( selected ) do
		
			// add the song to the list
			songs[ #songs + 1 ] = s.Filename;
		
		end
		
		// add the songs
		MuseX.AddToPlaylist( songs );
		
		// click the cancel button to close the panel
		self.GetParent( self ).Cancel:DoClick();
		
	end
	
	// create the cancel button
	self.Cancel = vgui.Create( "MXButton", self );
	// set the text
	self.Cancel:SetText( "#musex_cancel" );
	// setup the click function
	self.Cancel.DoClick = function( self )
		
		// close the file dialog
		self.GetParent( self ):Close();
		
		// clear the selection
		self.GetParent( self ).Files:ClearSelection();
		
	end
	
	// custom derma hooks
	Derma_Hook( self, "Paint", "Paint", "MXMainFrame" );
	Derma_Hook( self, "ApplySchemeSettings", "Scheme", "MXFrame" );
	self.AnimIn = Derma_Anim( "OpenAnim", self, self.OpenAnim );
	self.AnimOut = Derma_Anim( "CloseAnim", self, self.CloseAnim );

end


/*------------------------------------
	open the file dialog
------------------------------------*/
function PANEL:Open( )

	// ignore if we're already visible
	if ( self:IsVisible() ) then
	
		// bye
		return;
		
	end
	
	// close menus
	CloseDermaMenus();
	
	// take focus and be visible
	self:MakePopup();
	self:SetVisible( true );
	self:DoModal();
	
	// disable keyboard input
	self:SetKeyboardInputEnabled( false );
	
	// enable mouse input
	self:SetMouseInputEnabled( true );
	
	// halt the close animation
	self.AnimOut:Stop();
	
	// start the open animation
	self.AnimIn:Start( 0.1 );

end


/*------------------------------------
	handle the opening animation
------------------------------------*/
function PANEL:OpenAnim( anim, delta, data )

	// check if it has been started
	if ( anim.Started ) then
	
		// reset alpha
		self:SetAlpha( 0 );
		
	end
	
	// check if it has been finished
	if ( anim.Finished ) then
	
		// fully opaque
		self:SetAlpha( 255 );
		
		// start listing
		self:ListDirectory( MuseX.GetSetting( "filebrowsedir" ) );
		
		// all done
		return;
		
	end
	
	// animate the alpha
	self:SetAlpha( 255 * delta );

end


/*------------------------------------
	close the file dialog
------------------------------------*/
function PANEL:Close( skip )
	
	// close menus
	CloseDermaMenus();
	
	// halt the opening animation
	self.AnimIn:Stop();
	
	// check if we're skipping the animation
	if ( skip ) then
	
		// restore alpha
		self:SetAlpha( 255 );
		
		// not visible
		self:SetVisible( false );
	
	else
	
		// start the close animation
		self.AnimOut:Start( 0.1 );
		
	end

end


/*------------------------------------
	handle the closing animation
------------------------------------*/
function PANEL:CloseAnim( anim, delta, data )

	// check if the animation has started
	if ( anim.Started ) then
	
		// restore the alpha
		self:SetAlpha( 255 );
		
	end
	
	// check if the animation has finished
	if ( anim.Finished ) then
	
		// store alpha
		self:SetAlpha( 255 );
		
		// set as not visible
		self:SetVisible( false );
		
		// destroy
		self:Remove();
		
		// all done
		return;
		
	end
	
	// animate the alpha
	self:SetAlpha( 255 - 255 * delta );

end


/*------------------------------------
	layout the file dialog
------------------------------------*/
function PANEL:PerformLayout( )

	// BaseClass stuff
	self.BaseClass.PerformLayout( self );
	
	// size & position cancel button
	self.Cancel:SetSize( 75, 20 );
	self.Cancel:SetPos( self:GetWide() - 80, self:GetTall() - 25 );
	
	// size & position okay button
	self.Okay:SetSize( 75, 20 );
	self.Okay:SetPos( self:GetWide() - 160, self:GetTall() - 25 );
	
	// size & position divider
	self.Divider:SetSize( self:GetWide() - 10, self:GetTall() - 60 );
	self.Divider:SetPos( 5, 30 );
	
	// force the file list layout
	self.Files:SetDirty( true );
	self.Files:PerformLayout();
	
end


/*------------------------------------
	file dialog think
------------------------------------*/
function PANEL:Think( )

	// call BaseClass
	self.BaseClass.Think( self );
	
	// check if they finishing moving the window
	if ( !self.Dragging && self.WasDragging ) then
	
		// update position in settings
		MuseX.SetSetting( "filedialogx", self.X );
		MuseX.SetSetting( "filedialogy", self.Y );
		
	end
	
	// update previous dragging state
	self.WasDragging = self.Dragging;
	
	// run the animation functions
	self.AnimIn:Run();
	self.AnimOut:Run();

end


/* CUSTOM PANEL FUNCTIONS */


/*------------------------------------
	list the specified directory
------------------------------------*/
function PANEL:ListDirectory( path )

	// function to make sure the tooltip is long enough
	local FixedToolTip = function( panel, text )
	
		// make sure we have SOME text
		text = text or "";
		
		// minimum length
		local min = 8;
		
		// check if it is long enough
		if ( #text < min ) then
		
			// calculate the amount we need
			local amt = ( min - #text );
			
			// build the new text
			text = ("%s%s"):format( text, (" "):rep( amt ) );
		
		end
		
		// set the tool tip
		panel:SetToolTip( text );
	
	end
	
	// validate the path
	if ( path != "__drives__" && ( !path || !MXUtility.PathExists( path ) ) ) then
		
		// get the game application path and file
		local dir = MXUtility.GetGameExe();
		
		// strip the application
		dir = dir:sub( 1, #dir - 8 );
		
		// pretend this was our previous directory
		path = dir;
		
	end
	
	// loop FOREVER!
	while ( true ) do
	
		// get the last character
		local last = path:sub( #path, #path );
		
		// check if its a slash or a fucking asterisk (why does this thing keep popping up????)
		if ( last == "\\" || last == "*" ) then
		
			// if it is, remove it and keep looping
			path = path:sub( 1, #path - 1 );
			
		else
		
			// all done!
			break;
		
		end
	
	end

	// clear the folders and files list
	self.Folders:Clear();
	self.Files:Clear();
	
	// update the last browsed directory setting
	MuseX.SetSetting( "filebrowsedir", path );
	
	// make sure its not the "drives path", because we do special handling
	if ( path != "__drives__" ) then
	
		// get the directories and files
		local dirs, files = MXUtility.FindMedia( path );
		
		// check if it has a backslash, which means its a sub directory
		if ( path:find( "\\" ) ) then
	
			// remove the last directory
			local pathtbl = string.Explode( "\\", path );
			table.remove( pathtbl, #pathtbl );
			
			// create the "up one directory" path
			local uppath = table.concat( pathtbl, "\\" );
			
			// add it to the top
			local item = self.Folders:AddItem( "[..]" );
			
			// show them the parent path
			FixedToolTip( item, uppath );
			
			// store the file dialog for later use
			item.FileDialog = self;
			
			// setup the double click function
			item.DoDoubleClick = function( self )
			
				// list the directory
				self.FileDialog.ListDirectory( self.FileDialog, uppath );
				
			end
			
		else
		
			// add the "list drives" item
			local item = self.Folders:AddItem( "[..]" );
			
			// store the file dialog
			item.FileDialog = self;
			
			// set tooltip
			item:SetToolTip( "#musex_filedialog_drivelisttip" );
			
			// setup the double click function
			item.DoDoubleClick = function( self )
			
				// list the drives
				self.FileDialog.ListDirectory( self.FileDialog, "__drives__" );
				
			end
		
		end
		
		// if we found sub directories
		if ( dirs ) then
		
			// loop through the list
			for _, d in pairs( dirs ) do
			
				// build the new path
				local temppath = ("%s\\%s"):format( path, d );
				
				// create the item
				local item = self.Folders:AddItem( d );
				
				// save the file dialog
				item.FileDialog = self;
				
				// show them the full path
				FixedToolTip( item, temppath );
				
				// setup the double click function
				item.DoDoubleClick = function( self )
				
					// list the new directory
					self.FileDialog.ListDirectory( self.FileDialog, temppath );
					
				end
			
			end
		
		end
		
		// zeroed file count
		local filecount = 0;
		
		// check if we found files
		if ( files ) then
		
			// loop through the list of fi
			for _, f in pairs( files ) do
			
				// get the size of the file
				local size = MXUtility.GetMediaSize( ("%s\\%s"):format( path, f ) );
				
				// make sure we found the size
				if ( !size ) then
				
					// we didn't get the size, probably a read problem
					size = "???";
					
				else
				
					// format the bytes into a readable form
					size = util.FormatBytes( size );
					
				end
				
				// create the item
				local item = self.Files:AddLine( f, size );
				
				// store the filename
				item.Filename = ("%s\\%s"):format( path, f );
				
				// increment the filecount
				filecount = filecount + 1;
			
			end
			
		end
		
		// check if we didn't find any files
		if ( filecount == 0 ) then
		
			// add some text
			local item = self.Files:AddLine( "#musex_filedialog_nomedia" );
			
			// make sure it doesn't get added to the playlist
			item.Filename = "__nomedia__";
		
		end
		
	else
	
		// internal function
		local ListDrives = function( )
		
			// loop through list of drives
			for _, d in pairs( self.DriveCache ) do
			
				// build the new drive path
				local temppath = ("%s:\\"):format( d.letter );
				
				// create the item
				local item = self.Folders:AddItem( ("%s (%s:)"):format( MuseX.DriveType( d.type ), d.letter ) );
				
				// store the file dialog
				item.FileDialog = self;
				
				// setup the double click function
				item.DoDoubleClick = function( self )
				
					// list the path
					self.FileDialog.ListDirectory( self.FileDialog, temppath );
					
				end
			
			end
			
			// add some text
			local item = self.Files:AddLine( "#musex_filedialog_selectdrive" );
			
			// make sure it doesn't get added to the playlist
			item.Filename = "__nomedia__";
			
		end
	
		// check if we've already cached the drives
		if ( !self.DriveCache ) then
		
			// notify the client we're caching the drives
			self.Folders:AddItem( "#musex_filedialog_loading" );
			self.Files:AddLine( "#musex_filedialog_loadwait" );
			
			// delay accessing, otherwise they won't see the notifications
			timer.Simple( 0.01, function()
			
				// clear the notification shit
				self.Folders:Clear();
				self.Files:Clear();
			
				// get the drives
				self.DriveCache = MXUtility.FindDrives();
				
				// list the drives
				ListDrives();	
				
			end );
			
			// done for now
			return;
			
		else
		
			// list the drives
			ListDrives();
			
		end
		
	end
	
end

// define
derma.DefineControl( "MXFileDialog", "", PANEL, "DFrame" );
